package com.defangit.production.orm;

import com.defangit.production.domain.StockAlteration;
import com.defangit.production.orm.listeners.StockAlterationListener;
import laogen.hibernate.RandomOrderBuilder;
import laogen.hibernate.SessionFactoryProvider;
import laogen.hibernate.util.config.AbstractConfig;
import org.hibernate.boot.SessionFactoryBuilder;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.event.service.spi.EventListenerRegistry;
import org.hibernate.event.spi.EventType;
import org.slf4j.LoggerFactory;
import org.slf4j.Logger;
import org.hibernate.Interceptor;
import org.hibernate.SessionFactory;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;

import java.io.File;
import java.io.InputStream;
import java.util.List;


/**
 * Hibernate工具类
 */
public  class HibernateUtil extends SessionFactoryProvider {
    public static Logger HIBERNATE_LOGGER= LoggerFactory.getLogger("org.hibernate.SQL");
    public static final HibernateUtil INSTANCE;
    static{
        INSTANCE=new HibernateUtil();
        SessionFactoryProvider.INSTANCE=INSTANCE;
    }
    private HibernateUtil(){

    }

    private StandardServiceRegistry fromConfig(AbstractConfig _config){
        return new StandardServiceRegistryBuilder()

                //.applySetting("hibernate.driver_class", _config.driverClass())
                /*.applySetting("hibernate.connection.driver_class",_config.driverClass())
                .applySetting("hibernate.connection.url", _config.connectionUrl())
                .applySetting("hibernate.connection.username", _config.getUserName())
                .applySetting("hibernate.connection.password",_config.getPassword())*/

                .applySetting("testWhileIdle","true")
                .applySetting("initialSize","3")
                .applySetting("minIdle","3")
                .applySetting("maxActive",GlobalConfig.DB_MAX_CONNECTION.getValue().toString())
                .applySetting("driverClassName",_config.driverClass())
                .applySetting("url", _config.connectionUrl())
                .applySetting("username", _config.getUserName())
                .applySetting("password",_config.getPassword())
                .applySetting("hibernate.dialect",_config.dialect())
                .applySetting("hibernate.hbm2ddl.auto",_config.getHbm2ddl())
                /*todo 会影响性能
                .applySetting("hibernate.show_sql","false")
                .applySetting("hibernate.format_sql","true")
                .applySetting("hibernate.use_sql_comments","true")*/
                /**current session context class :(JTA & thread)控制currentSession处理机制*/
                .applySetting("hibernate.current_session_context_class","thread")
                .applySetting("hibernate.connection.provider_class","com.alibaba.druid.support.hibernate.DruidConnectionProvider")
                /*.applySetting("hibernate.c3p0.max_size", 810)
                .applySetting("hibernate.c3p0.min_size", 30)
                .applySetting("hibernate.c3p0.timeout",25000)
                .applySetting("hibernate.c3p0.acquire_increment",3)
                .applySetting("hibernate.c3p0.idle_test_period",300)*/
                .applySetting("hibernate.jdbc.batch_size",50)
                .applySetting("hibernate.jdbc.fetch_size",50)
                /*.applySetting("hibernate.c3p0.max_statements",100)
                .applySetting("hibernate.c3p0.maxStatementsPerConnection",100)
                .applySetting("hibernate.c3p0.debugUnreturnedConnectionStackTraces",true)
                .applySetting("hibernate.c3p0.unreturnedConnectionTimeout",240)
                .applySetting("hibernate.c3p0.acquireRetryAttempts",3)
                .applySetting("hibernate.c3p0.acquireRetryDelay",1000)
                .applySetting("hibernate.c3p0.numHelperThreads",10)*/
                //.applySetting("hibernate.c3p0.testConnectionOnCheckout",true)
                .applySetting("hibernate.connection.isolation",2)//事务隔离级别
                .applySetting("hibernate.connection.release_mode","on_close")
                .build();
    }
    public  void setDataSourceConfig(AbstractConfig _serverConfig) {
        serverConfig=_serverConfig;
        if(sessionFactory!=null) sessionFactory.close();
        sessionFactory=null;
    }

    private AbstractConfig serverConfig;
    private SessionFactory sessionFactory;
    public SessionFactory getSessionFactory() {
        if(sessionFactory==null||sessionFactory.isClosed()){
            StandardServiceRegistry registry=fromConfig(serverConfig);
            MetadataSources _src=new MetadataSources(registry)
                    .addResource("hbms/process.hbm.xml")
                    .addResource("hbms/manufacture.hbm.xml")
                    .addResource("hbms/manufacture-item.hbm.xml")
                    .addResource("hbms/operator.hbm.xml");
            _src.addResource("hbms/production-process.hbm.xml")
                    .addResource("hbms/time-sheet.hbm.xml")
                    .addResource("hbms/material-bill.hbm.xml")
                    .addResource("hbms/production-bill.hbm.xml");
            _src.addResource("querys/stock_mysql.hbm.xml")
                    .addResource("hbms/manufacture-entry.hbm.xml")
                    .addResource("hbms/store.hbm.xml")
                    .addResource("hbms/stock.hbm.xml")
                    .addResource("hbms/stock-alteration.hbm.xml")
                    .addResource("hbms/materialsbill.hbm.xml")
                    .addResource("hbms/transfer-entry.hbm.xml")
                    .addResource("hbms/process-time.hbm.xml")
                    .addResource("hbms/manufacture-from.hbm.xml");
                    //.addDirectory(new File("hbms"));
            //
            //_src.getMetadataBuilder().applyAttributeConverter(QuestionTypeConverter.INSTANCE,true);
            /*List<ORMMappingEp> mappingEps=PluginManager.getInstance().getListeners(ORMMappingEp.class);
            mappingEps.forEach(ep->{
                List<InputStream> mappings=ep.extraMappings();
                if(mappings!=null){
                    mappings.forEach(_src::addInputStream);
                }
            });*/
            if(serverConfig.dialect().contains("Derby")) RandomOrderBuilder.setDefaultRandomOrder(RandomOrderBuilder.DerbyRandomOrder());


            SessionFactoryBuilder builder=_src.buildMetadata().getSessionFactoryBuilder();
            /*PluginManager.getInstance().getListeners(Interceptor.class)
                    .forEach(builder::applyInterceptor);*/
            sessionFactory =builder.build();
            ((SessionFactoryImplementor)sessionFactory).getServiceRegistry()
                    .getService(EventListenerRegistry.class)
                    .appendListeners(EventType.POST_INSERT, StockAlterationListener.class);
        }
        return sessionFactory;
    }
}
